package com.xyht.medicine_management_system.modules.order.scheduleTask;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wechat.pay.java.service.refund.model.Refund;
import com.xyht.medicine_management_system.common.util.TimeUtil;
import com.xyht.medicine_management_system.modules.consumptionPoint.constant.ConsumptionPointRecordConstant;
import com.xyht.medicine_management_system.modules.consumptionPoint.entity.MmsConsumptionPointRecord;
import com.xyht.medicine_management_system.modules.consumptionPoint.entity.MmsUserConsumptionPoint;
import com.xyht.medicine_management_system.modules.consumptionPoint.mapper.MmsConsumptionPointRecordMapper;
import com.xyht.medicine_management_system.modules.consumptionPoint.mapper.MmsUserConsumptionPointMapper;
import com.xyht.medicine_management_system.modules.consumptionPoint.service.MmsConsumptionPointRecordService;
import com.xyht.medicine_management_system.modules.coupon.constant.UserCouponRelationConstant;
import com.xyht.medicine_management_system.modules.coupon.entity.MmsUserCouponRelation;
import com.xyht.medicine_management_system.modules.coupon.entity.resp.MmsUserCouponRelationResp;
import com.xyht.medicine_management_system.modules.coupon.service.MmsUserCouponRelationService;
import com.xyht.medicine_management_system.modules.order.constant.OrderConstant;
import com.xyht.medicine_management_system.modules.order.constant.OrderRefundConstant;
import com.xyht.medicine_management_system.modules.order.constant.OrderScheduleConstant;
import com.xyht.medicine_management_system.modules.order.constant.ProcessApproverConstant;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrder;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderRefund;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderSchedule;
import com.xyht.medicine_management_system.modules.order.service.MmsOrderRefundService;
import com.xyht.medicine_management_system.modules.order.service.MmsOrderScheduleService;
import com.xyht.medicine_management_system.modules.order.service.MmsOrderService;
import com.xyht.medicine_management_system.modules.order.util.OrderScheduleUtil;
import com.xyht.medicine_management_system.modules.order.util.OrderUtil;
import com.xyht.medicine_management_system.modules.payment.alipay.util.AliPayUtil;
import com.xyht.medicine_management_system.modules.payment.entity.OrderQueryResponse;
import com.xyht.medicine_management_system.modules.payment.entity.RefundResponse;
import com.xyht.medicine_management_system.modules.payment.util.PaymentUtil;
import com.xyht.medicine_management_system.modules.payment.wxpay.entity.RefundReq;
import com.xyht.medicine_management_system.modules.payment.wxpay.util.WxPayUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.xyht.medicine_management_system.common.util.ParamCheckUtil.isNullOrEmpty;

@Component
@Log4j2
public class OrderScheduleTask {
    @Resource
    private MmsOrderScheduleService mmsOrderScheduleService;
    @Resource
    private MmsOrderService mmsOrderService;
    @Resource
    private MmsOrderRefundService mmsOrderRefundService;
    @Resource
    private PaymentUtil paymentUtil;
    @Resource
    private OrderUtil orderUtil;
    @Resource
    private MmsUserCouponRelationService mmsUserCouponRelationService;
    @Resource
    private OrderScheduleUtil orderScheduleUtil;
    @Resource
    private MmsConsumptionPointRecordMapper mmsConsumptionPointRecordMapper;
    @Resource
    private MmsUserConsumptionPointMapper mmsUserConsumptionPointMapper;

    @Resource
    private PlatformTransactionManager transactionManager; // 事务

    @Scheduled(cron = "0 */1 * * * ?") // 每隔1分钟执行一次
    public void schedulingTask() {
        // 获取所有 未结束且已达过期时间 的定时任务
        Date nowDate = new Date(); // 当前时间
        List<MmsOrderSchedule> orderScheduleList = mmsOrderScheduleService.list(new LambdaQueryWrapper<MmsOrderSchedule>()
                .eq(MmsOrderSchedule::getIsClose, false) // 状态未结束
                .le(MmsOrderSchedule::getExpireTime, nowDate)); // 过期时间 早于 当前时间
        if (orderScheduleList.isEmpty()) { // 没有定时任务直接结束方法
            return;
        }

        for (MmsOrderSchedule orderSchedule : orderScheduleList) {
            // 开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);

            try {
                // 获取定时任务订单
                MmsOrder order = mmsOrderService.getById(orderSchedule.getOrderId());
                if (order == null) { //订单不存在
                    continue;
                }

                // 根据 进度类型(0.支付进度 1.发货进度 2.订单结束进度) 进行不同处理
                switch (orderSchedule.getType()) {
                    case OrderScheduleConstant.ORDER_SCHEDULE_TYPE_PAYMENT: // 支付进度
                        // 主动查询用户支付情况
                        OrderQueryResponse orderQueryResponse = paymentUtil.queryOrderByOutTradeNo(order.getId(), order.getPaymentMethod());
                        // 用户支付成功
                        if (orderQueryResponse != null) {
                            if (!orderUtil.isPaid(order.getId())) { // 订单没有支付信息
                                // 修改订单状态等信息
                                order.setPaymentTransactionId(orderQueryResponse.getTransactionId()); // 平台交易订单号
                                order.setPaymentAmount(centsToYuan(orderQueryResponse.getTotal())); // 支付金额
                                order.setPaymentTime(orderQueryResponse.getSuccessTime()); // 支付时间
                                order.setOrderStatus(OrderConstant.ORDER_STATUS_TO_BE_DELIVERED); // 待发货

                                // 创建订单定时任务(发货进度)
                                int deliveryOrderScheduleNum = orderScheduleUtil.getOrderScheduleNum(order.getId(), OrderScheduleConstant.ORDER_SCHEDULE_TYPE_DELIVERY);
                                if (deliveryOrderScheduleNum <= 0) {
                                    rollback(status); // 手动回滚事务
                                    continue;
                                }
                                MmsOrderSchedule deliverySchedule = orderScheduleUtil.generateOrderScheduleByType(
                                        order.getId(),
                                        OrderScheduleConstant.ORDER_SCHEDULE_TYPE_DELIVERY,
                                        OrderScheduleConstant.ORDER_SCHEDULE_CREATOR_SYSTEM,
                                        orderQueryResponse.getSuccessTime());
                                if (deliverySchedule == null) {
                                    rollback(status); // 手动回滚事务
                                    continue;
                                }

                                // 创建订单定时任务(订单结束进度)
                                int endOrderScheduleNum = orderScheduleUtil.getOrderScheduleNum(order.getId(), OrderScheduleConstant.ORDER_SCHEDULE_TYPE_ORDER_END);
                                if (endOrderScheduleNum <= 0) {
                                    rollback(status); // 手动回滚事务
                                    continue;
                                }
                                MmsOrderSchedule orderEndSchedule = orderScheduleUtil.generateOrderScheduleByType(
                                        order.getId(),
                                        OrderScheduleConstant.ORDER_SCHEDULE_TYPE_ORDER_END,
                                        OrderScheduleConstant.ORDER_SCHEDULE_CREATOR_SYSTEM,
                                        orderQueryResponse.getSuccessTime());
                                if (orderEndSchedule == null) {
                                    rollback(status); // 手动回滚事务
                                    continue;
                                }
                            }
                        } else { // 支付失败
                            order.setOrderStatus(OrderConstant.ORDER_STATUS_ORDER_CANCELLED); // 订单状态: 0.取消订单
                            order.setIsClose(OrderConstant.ORDER_IS_CLOSE_YES); // 结束订单
                            order.setEndTime(nowDate); // 订单结束时间
                        }

                        break;
                    case OrderScheduleConstant.ORDER_SCHEDULE_TYPE_DELIVERY: // 发货进度
                        order.setOrderStatus(OrderConstant.ORDER_STATUS_ORDER_CANCELLED); // 订单状态: 0.取消订单
                        order.setIsClose(OrderConstant.ORDER_IS_CLOSE_YES); // 结束订单
                        order.setEndTime(nowDate); // 订单结束时间

                        // 付款金额大于0,自动退款
                        if (order.getPaymentAmount().compareTo(BigDecimal.valueOf(0)) > 0) {
                            // 查询不到支付订单号直接回滚
                            if (isNullOrEmpty(order.getPaymentTransactionId())) {
                                rollback(status); // 手动回滚事务
                                continue;
                            }

                            // 待退款中的订单改为退款失败
                            List<MmsOrderRefund> orderRefundList = mmsOrderRefundService.list(new LambdaQueryWrapper<MmsOrderRefund>()
                                    .eq(MmsOrderRefund::getOrderId, order.getId()) // 订单编号
                                    .eq(MmsOrderRefund::getStatus, OrderRefundConstant.ORDER_REFUND_STATUS_TO_BE_REFUNDED)); // 待退款
                            if (!orderRefundList.isEmpty()) {
                                MmsOrderRefund orderRefund = new MmsOrderRefund();
                                orderRefund.setStatus(OrderRefundConstant.ORDER_REFUND_STATUS_REFUNDED_FAIL); // 退款失败
                                List<String> orderRefundIdList = orderRefundList.stream().map(MmsOrderRefund::getId).collect(Collectors.toList());
                                boolean refundUpdSuccess = mmsOrderRefundService.update(orderRefund, new LambdaQueryWrapper<MmsOrderRefund>()
                                        .in(MmsOrderRefund::getId, orderRefundIdList));
                                if (!refundUpdSuccess) { //修改失败
                                    rollback(status); // 手动回滚事务
                                    continue;
                                }
                            }

                            // 记录退款行为
                            MmsOrderRefund orderRefund = new MmsOrderRefund();
                            orderRefund.setUserId(order.getUserId());
                            orderRefund.setOrderId(order.getId());
                            orderRefund.setMedicineInfo(order.getMedicineInfo());
                            orderRefund.setStatus(OrderRefundConstant.ORDER_REFUND_STATUS_REFUNDING); // 退货状态: 退款中
                            orderRefund.setProcessApproverId(ProcessApproverConstant.PROCESS_APPROVER_SYSTEM); // 审批人: 系统-定时任务
                            orderRefund.setNotes(OrderRefundConstant.ORDER_REFUND_REASON_DELIVERY_TIMEOUT);
                            boolean refundSaveSuccess = mmsOrderRefundService.save(orderRefund);
                            if (!refundSaveSuccess) {
                                rollback(status); // 手动回滚事务
                                continue;
                            }

                            // 发起预退款
                            RefundReq preRefundReq = new RefundReq();
                            preRefundReq.setTransaction_id(order.getPaymentTransactionId()); // 微信交易订单号
                            preRefundReq.setOut_trade_no(order.getId()); // 商户订单号
                            preRefundReq.setOut_refund_no(orderRefund.getId()); // 退款单号
                            preRefundReq.setReason(OrderRefundConstant.ORDER_REFUND_REASON_USER_SUBMIT); // 退款原因: 用户申请退款
                            // 设置订单金额 单位：分(订单金额 = 原金额(元) * 100)
                            long total = order.getPaymentAmount().multiply(BigDecimal.valueOf(100)).longValue();
                            preRefundReq.setTotal(total); // 订单金额 单位：分
                            preRefundReq.setRefund(total); // 退款金额 单位：分(全部退)
                            preRefundReq.setPaymentMethod(order.getPaymentMethod()); // 退款金额 单位：分(全部退)
                            RefundResponse refund = paymentUtil.createRefund(preRefundReq);
                            if (refund == null) {
                                rollback(status); // 手动回滚事务
                                continue;
                            }

                            // 修改退款记录
                            orderRefund.setRefundId(refund.getRefundTradeId()); // 退款单号
                            orderRefund.setRefundAmount(centsToYuan(refund.getTotal())); // 退款金额
                            orderRefund.setRefundTime(refund.getSuccessTime()); // 退款时间
                            orderRefund.setStatus(OrderRefundConstant.ORDER_REFUND_STATUS_REFUNDED); // 退货状态: 已退款
                            boolean refundUpdSuccess = mmsOrderRefundService.updateById(orderRefund);
                            if (!refundUpdSuccess) {
                                rollback(status); // 手动回滚事务
                                continue;
                            }
                        }

                        // 退还优惠券
                        if (!isNullOrEmpty(order.getCouponInfo())) { // 存在优惠券信息
                            MmsUserCouponRelationResp couponInfo = JSONObject.parseObject(order.getCouponInfo(), MmsUserCouponRelationResp.class);
                            if (couponInfo != null) {
                                MmsUserCouponRelation userCoupon = mmsUserCouponRelationService.getById(couponInfo.getId());
                                if (userCoupon != null) {
                                    // 优惠券状态修改为未使用
                                    userCoupon.setIsUse(UserCouponRelationConstant.USER_COUPON_RELATION_NOT_USE);
                                    boolean couponUpdSuccess = mmsUserCouponRelationService.updateById(userCoupon);
                                    if (!couponUpdSuccess) { // 修改失败
                                        rollback(status); // 手动回滚事务
                                        continue;
                                    }
                                }
                            }
                        }

                        // 退还积分
                        if (order.getIsUsePoint() != null && order.getIsUsePoint()) {
                            MmsConsumptionPointRecord pointRecord = mmsConsumptionPointRecordMapper.selectById(order.getPointRecordId());

                            // 添加退还记录
                            MmsConsumptionPointRecord backPointRecord = new MmsConsumptionPointRecord();
                            BeanUtils.copyProperties(pointRecord, backPointRecord, "id");
                            backPointRecord.setStatus(ConsumptionPointRecordConstant.POINT_RECORD_STATUS_INCREASE);
                            mmsConsumptionPointRecordMapper.insert(backPointRecord);

                            // 退还积分
                            List<MmsUserConsumptionPoint> userPointList = mmsUserConsumptionPointMapper.selectList(new LambdaQueryWrapper<MmsUserConsumptionPoint>()
                                    .eq(MmsUserConsumptionPoint::getUserId, order.getUserId()));
                            MmsUserConsumptionPoint userPoint = userPointList.get(0);
                            // 当前积分 = 原积分 + 退还积分
                            userPoint.setPoints(userPoint.getPoints() + pointRecord.getPoints());
                            mmsUserConsumptionPointMapper.updateById(userPoint);
                        }

                        break;
                    case OrderScheduleConstant.ORDER_SCHEDULE_TYPE_ORDER_END: // 订单结束进度
                        order.setOrderStatus(OrderConstant.ORDER_STATUS_ALREADY_RECEIVED); // 订单状态: 4.已收货
                        order.setIsClose(OrderConstant.ORDER_IS_CLOSE_YES); // 结束订单
                        order.setEndTime(nowDate); // 订单结束时间

                        // 发起分账
                        // 支付订单号不存在
                        if (isNullOrEmpty(order.getPaymentTransactionId())) {
                            continue;
                        }
                        paymentUtil.profitSharingUnfreezeOrder(order.getId(), order.getPaymentTransactionId(), order.getPaymentMethod());

                        // 待退款中的订单改为退款失败
                        List<MmsOrderRefund> orderRefundList = mmsOrderRefundService.list(new LambdaQueryWrapper<MmsOrderRefund>()
                                .eq(MmsOrderRefund::getOrderId, order.getId()) // 订单编号
                                .eq(MmsOrderRefund::getStatus, OrderRefundConstant.ORDER_REFUND_STATUS_TO_BE_REFUNDED)); // 待退款
                        if (!orderRefundList.isEmpty()) {
                            MmsOrderRefund orderRefund = new MmsOrderRefund();
                            orderRefund.setStatus(OrderRefundConstant.ORDER_REFUND_STATUS_REFUNDED_FAIL); // 退款失败
                            List<String> orderRefundIdList = orderRefundList.stream().map(MmsOrderRefund::getId).collect(Collectors.toList());
                            boolean refundUpdSuccess = mmsOrderRefundService.update(orderRefund, new LambdaQueryWrapper<MmsOrderRefund>()
                                    .in(MmsOrderRefund::getId, orderRefundIdList));
                            if (!refundUpdSuccess) { //修改失败
                                rollback(status); // 手动回滚事务
                                continue;
                            }
                        }

                        break;
                }

                // 修改订单
                boolean orderUpdSuccess = mmsOrderService.updateById(order);
                if (!orderUpdSuccess) {
                    rollback(status); // 手动回滚事务
                    continue;
                }

                // 关闭定时任务
                orderSchedule.setIsClose(true); // 结束定时任务
                orderSchedule.setEndTime(nowDate); // 结束时间
                orderSchedule.setUpdateUserId(ProcessApproverConstant.PROCESS_APPROVER_SYSTEM); // 修改人
                boolean scheduleUpdSuccess = mmsOrderScheduleService.updateById(orderSchedule);
                if (!scheduleUpdSuccess) {
                    rollback(status); // 手动回滚事务
                    continue;
                }
            } catch (Exception e) {
                e.printStackTrace();
                // 手动回滚事务
                transactionManager.rollback(status);
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                }
            }
        }
    }

    /**
     * 将以分为单位的金额转换为以元为单位的金额(BigDecimal)
     *
     * @param <T>          可以是Integer或Long类型
     * @param moneyInCents 以分为单位的金额(T)
     * @return 以元为单位的金额(BigDecimal)
     */
    private <T extends Number> BigDecimal centsToYuan(T moneyInCents) {
        // 将分转换为元, 需要除以100, 并将结果存储为BigDecimal类型
        return new BigDecimal(moneyInCents.longValue()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
    }

    /**
     * 手动回滚事务
     *
     * @param status 嵌套事务
     */
    private void rollback(TransactionStatus status) {
        // 手动回滚事务
        transactionManager.rollback(status);
        if (status.isNewTransaction() && !status.isCompleted()) {
            transactionManager.commit(status);
        }
    }

}
